home *** CD-ROM | disk | FTP | other *** search
/ AMIGA-CD 2 / Amiga-CD - Volume 2.iso / ungepackte_daten / 1994 / 8 / 05 / term-4.0-source.lha / termSound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-17  |  21.6 KB  |  1,086 lines

  1. /*
  2. **    termSound.c
  3. **
  4. **    Sound support routines
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Double buffering chunk size. */
  13.  
  14. #define BUFFER_SIZE    32768
  15.  
  16.     /* Maximum replay volume. */
  17.  
  18. #define MAX_VOLUME    64
  19.  
  20.     /* Stereo/channel sample type. */
  21.  
  22. typedef LONG        SampleType;
  23.  
  24.     /* Channel definitions. */
  25.  
  26. #define SAMPLE_LEFT    2
  27. #define SAMPLE_RIGHT    4
  28. #define SAMPLE_STEREO    6
  29.  
  30.     /* A fixed-point value, 16 bits to the left of
  31.      * the point and 16 to the right. A Fixed is a
  32.      * number of 2**16ths, i.e. 65536ths.
  33.      */
  34.  
  35. typedef LONG        Fixed;
  36.  
  37.     /* Unity = Fixed 1.0 = maximum volume */
  38.  
  39. #define Unity        0x10000L
  40.  
  41.     /* Sample compression modes. */
  42.  
  43. #define sCmpNone    0
  44. #define sCmpFibDelta    1
  45.  
  46.     /* The voice header. */
  47.  
  48. typedef struct
  49. {
  50.     ULONG    oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  51.         repeatHiSamples,    /* # samples in the high octave repeat part */
  52.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
  53.     UWORD    samplesPerSec;        /* data sampling rate */
  54.     UBYTE    ctOctave,        /* # of octaves of waveforms */
  55.         sCompression;        /* data compression technique used */
  56.     Fixed    volume;            /* playback nominal volume from 0 to Unity
  57.                      * (full volume). Map this value into
  58.                      * the output hardware's dynamic range.
  59.                      */
  60. } Voice8Header;
  61.  
  62.     /* Double-buffering information. */
  63.  
  64. struct BufferInfo
  65. {
  66.     LONG    Size;
  67.     UBYTE    Buffer[BUFFER_SIZE];
  68. };
  69.  
  70.     /* Sound replay information. */
  71.  
  72. struct SoundInfo
  73. {
  74.     UBYTE    Name[MAX_FILENAME_LENGTH];
  75.  
  76.     ULONG    Rate,
  77.         Length,
  78.         Volume;
  79.  
  80.     APTR    SoundData;
  81.  
  82.     APTR    LeftData,
  83.         RightData;
  84. };
  85.  
  86.     /* Local data. */
  87.  
  88. STATIC struct SignalSemaphore    *SoundSemaphore;
  89. STATIC struct SoundInfo        *SoundSlot[SOUND_COUNT];
  90.  
  91.     /* DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst):
  92.      *
  93.      *    Unpack Fibonacci-delta-encoded data.
  94.      */
  95.  
  96. STATIC VOID __regargs
  97. DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst)
  98. {
  99.     STATIC BYTE CodeToDelta[16] = { -34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21 };
  100.  
  101.     BYTE    Value = (BYTE)Src[1];
  102.     UBYTE    Code;
  103.  
  104.         /* Skip the header information. */
  105.  
  106.     Src    += 2;
  107.     Size    -= 2;
  108.  
  109.         /* Run down the chunk... */
  110.  
  111.     while(Size--)
  112.     {
  113.         Code = *Src++;
  114.  
  115.             /* Add the top nibble delta. */
  116.  
  117.         Value += CodeToDelta[Code >> 4];
  118.  
  119.         *Dst++ = Value;
  120.  
  121.             /* Add the bottom nibble delta. */
  122.  
  123.         Value += CodeToDelta[Code & 0xF];
  124.  
  125.         *Dst++ = Value;
  126.     }
  127. }
  128.  
  129.     /* FreeSound(struct SoundInfo *SoundInfo):
  130.      *
  131.      *    Free sound handle and associated data.
  132.      */
  133.  
  134. VOID __regargs
  135. FreeSound(struct SoundInfo *SoundInfo)
  136. {
  137.     FreeVecPooled(SoundInfo -> SoundData);
  138.     FreeVecPooled(SoundInfo);
  139. }
  140.  
  141.     /* LoadSound(STRPTR Name):
  142.      *
  143.      *    Load a sound file from disk.
  144.      */
  145.  
  146. struct SoundInfo * __regargs
  147. LoadSound(STRPTR Name,BYTE Warn)
  148. {
  149.     struct SoundInfo    *SoundInfo = NULL;
  150.     struct IFFHandle    *Handle;
  151.  
  152.         /* Allocate IFF handle for reading. */
  153.  
  154.     if(Handle = AllocIFF())
  155.     {
  156.             /* Open a standard DOS stream. */
  157.  
  158.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  159.         {
  160.                 /* Say it's a DOS stream. */
  161.  
  162.             InitIFFasDOS(Handle);
  163.  
  164.                 /* Open the file for reading. */
  165.  
  166.             if(!OpenIFF(Handle,IFFF_READ))
  167.             {
  168.                 LONG SoundStops[3 * 2] =
  169.                 {
  170.                     ID_8SVX,ID_VHDR,
  171.                     ID_8SVX,ID_CHAN,
  172.                     ID_8SVX,ID_BODY
  173.                 };
  174.  
  175.                     /* Mark the chunks to stop at. */
  176.  
  177.                 if(!StopChunks(Handle,SoundStops,3))
  178.                 {
  179.                     struct ContextNode    *Chunk;
  180.                     Voice8Header         Header;
  181.                     UBYTE             Compression;
  182.                     SampleType         Channel    = SAMPLE_STEREO;
  183.                     BYTE             SingleChannel    = TRUE;
  184.  
  185.                         /* Clear the voice header. */
  186.  
  187.                     memset(&Header,0,sizeof(Voice8Header));
  188.  
  189.                         /* Scan for data... */
  190.  
  191.                     while(!ParseIFF(Handle,IFFPARSE_SCAN))
  192.                     {
  193.                         Chunk = CurrentChunk(Handle);
  194.  
  195.                             /* What did we find? */
  196.  
  197.                         switch(Chunk -> cn_ID)
  198.                         {
  199.                                 /* Looks like the basic voice header. */
  200.  
  201.                             case ID_VHDR:
  202.  
  203.                                     /* Read the header. */
  204.  
  205.                                 if(ReadChunkRecords(Handle,&Header,MIN(Chunk -> cn_Size,sizeof(Voice8Header)),1) == 1)
  206.                                 {
  207.                                         /* Compression type supported? */
  208.  
  209.                                     if(Header . sCompression == sCmpNone || Header . sCompression == sCmpFibDelta)
  210.                                     {
  211.                                             /* Allocate the sound handle. */
  212.  
  213.                                         if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  214.                                         {
  215.                                                 /* Install the rate, volume and length. */
  216.  
  217.                                             SoundInfo -> Rate    = SysBase -> ex_EClockFrequency * 5 / Header . samplesPerSec;
  218.                                             SoundInfo -> Length    = Header . oneShotHiSamples ? Header . oneShotHiSamples : Header . repeatHiSamples;
  219.                                             SoundInfo -> Volume    = (SoundConfig . Volume * ((Header . volume * MAX_VOLUME) / Unity)) / 100;
  220.  
  221.                                                 /* Remember compression mode. */
  222.  
  223.                                             Compression        = Header . sCompression;
  224.                                         }
  225.                                     }
  226.                                 }
  227.  
  228.                                 break;
  229.  
  230.                                 /* Looks like sound channel information. */
  231.  
  232.                             case ID_CHAN:
  233.  
  234.                                     /* Do we have a handle to manage it? */
  235.  
  236.                                 if(SoundInfo)
  237.                                 {
  238.                                         /* Read the channel information. */
  239.  
  240.                                     if(ReadChunkRecords(Handle,&Channel,MIN(Chunk -> cn_Size,sizeof(SampleType)),1) == 1)
  241.                                     {
  242.                                             /* Stereo sound file? */
  243.  
  244.                                         if(Channel == SAMPLE_STEREO)
  245.                                             SingleChannel = FALSE;
  246.                                     }
  247.                                     else
  248.                                     {
  249.                                         FreeVecPooled(SoundInfo);
  250.  
  251.                                         SoundInfo = NULL;
  252.                                     }
  253.                                 }
  254.  
  255.                                 break;
  256.  
  257.                                 /* Looks like the sound body data. */
  258.  
  259.                             case ID_BODY:
  260.  
  261.                                     /* Do we have sound handle to manage it? */
  262.  
  263.                                 if(SoundInfo)
  264.                                 {
  265.                                     BYTE Success = FALSE;
  266.  
  267.                                         /* Uncompressed raw data? */
  268.  
  269.                                     if(Compression == sCmpNone)
  270.                                     {
  271.                                         ULONG Wanted;
  272.  
  273.                                         if(Channel == SAMPLE_STEREO && !SingleChannel)
  274.                                         {
  275.                                             Wanted = SoundInfo -> Length * 2;
  276.  
  277.                                             if(Wanted > Chunk -> cn_Size)
  278.                                             {
  279.                                                 SoundInfo -> Length /= 2;
  280.  
  281.                                                 Wanted = SoundInfo -> Length * 2;
  282.                                             }
  283.                                         }
  284.                                         else
  285.                                             Wanted = SoundInfo -> Length;
  286.  
  287.                                         if(Chunk -> cn_Size >= Wanted)
  288.                                         {
  289.                                                 /* Allocate a buffer. */
  290.  
  291.                                             if(SoundInfo -> SoundData = AllocVecPooled(Wanted,MEMF_ANY))
  292.                                             {
  293.                                                     /* Read the data. */
  294.  
  295.                                                 if(ReadChunkRecords(Handle,SoundInfo -> SoundData,Wanted,1) == 1)
  296.                                                     Success = TRUE;
  297.                                                 else
  298.                                                     FreeVecPooled(SoundInfo -> SoundData);
  299.                                             }
  300.                                         }
  301.                                     }
  302.                                     else
  303.                                     {
  304.                                         ULONG Wanted;
  305.  
  306.                                         if(Channel == SAMPLE_STEREO && !SingleChannel)
  307.                                         {
  308.                                             Wanted = SoundInfo -> Length + 4;
  309.  
  310.                                             if(Wanted > Chunk -> cn_Size)
  311.                                             {
  312.                                                 SoundInfo -> Length /= 2;
  313.  
  314.                                                 Wanted = SoundInfo -> Length * 2 + 4;
  315.  
  316.                                                 SingleChannel = TRUE;
  317.                                             }
  318.                                         }
  319.                                         else
  320.                                             Wanted = SoundInfo -> Length / 2 + 2;
  321.  
  322.                                         if(Chunk -> cn_Size >= Wanted)
  323.                                         {
  324.                                             UBYTE    *TempBuffer;
  325.  
  326.                                                 /* Allocate a temporary decompression buffer. */
  327.  
  328.                                             if(TempBuffer = (UBYTE *)AllocVecPooled(Chunk -> cn_Size,MEMF_ANY))
  329.                                             {
  330.                                                     /* Read the compressed data. */
  331.  
  332.                                                 if(ReadChunkRecords(Handle,TempBuffer,Chunk -> cn_Size,1) == 1)
  333.                                                 {
  334.                                                     ULONG Length = SoundInfo -> Length;
  335.  
  336.                                                         /* Allocate space for the uncompressed data. */
  337.  
  338.                                                     if(SoundInfo -> SoundData = AllocVecPooled(Length * 2,MEMF_ANY))
  339.                                                     {
  340.                                                             /* Stereo sound file? */
  341.  
  342.                                                         if(!SingleChannel && Channel == SAMPLE_STEREO)
  343.                                                         {
  344.                                                             UBYTE *Data = SoundInfo -> SoundData;
  345.  
  346.                                                                 /* Unpack the stereo sound. */
  347.  
  348.                                                             DeltaUnpack(TempBuffer,                 Length / 2 + 2,Data);
  349.                                                             DeltaUnpack(TempBuffer + Length / 2 + 2,Length / 2 + 2,Data + Length);
  350.                                                         }
  351.                                                         else
  352.                                                         {
  353.                                                                 /* Unpack the mono sound. */
  354.  
  355.                                                             DeltaUnpack(TempBuffer,Length / 2 + 2,SoundInfo -> SoundData);
  356.                                                         }
  357.  
  358.                                                         Success = TRUE;
  359.                                                     }
  360.                                                 }
  361.  
  362.                                                 FreeVecPooled(TempBuffer);
  363.                                             }
  364.                                         }
  365.                                     }
  366.  
  367.                                     if(!Success)
  368.                                     {
  369.                                         FreeVecPooled(SoundInfo);
  370.  
  371.                                         SoundInfo = NULL;
  372.                                     }
  373.                                 }
  374.  
  375.                                 break;
  376.                         }
  377.                     }
  378.  
  379.                         /* Did we get what we wanted? */
  380.  
  381.                     if(SoundInfo)
  382.                     {
  383.                             /* Any sound data allocated? */
  384.  
  385.                         if(SoundInfo -> SoundData)
  386.                         {
  387.                             UBYTE *Data = SoundInfo -> SoundData;
  388.  
  389.                                 /* Which kind of sound file did
  390.                                  * we read?
  391.                                  */
  392.  
  393.                             switch(Channel)
  394.                             {
  395.                                     /* Left channel only. */
  396.  
  397.                                 case SAMPLE_LEFT:
  398.  
  399.                                     SoundInfo -> LeftData = Data;
  400.                                     break;
  401.  
  402.                                     /* Right channel only. */
  403.  
  404.                                 case SAMPLE_RIGHT:
  405.  
  406.                                     SoundInfo -> RightData = Data;
  407.                                     break;
  408.  
  409.                                     /* Two stereo channels. */
  410.  
  411.                                 case SAMPLE_STEREO:
  412.  
  413.                                         /* One sound mapped to two voices. */
  414.  
  415.                                     if(SingleChannel)
  416.                                         SoundInfo -> LeftData = SoundInfo -> RightData = Data;
  417.                                     else
  418.                                     {
  419.                                             /* Split the voice data. */
  420.  
  421.                                         SoundInfo -> LeftData    = Data;
  422.                                         SoundInfo -> RightData    = Data + SoundInfo -> Length;
  423.                                     }
  424.  
  425.                                     break;
  426.                             }
  427.                         }
  428.                         else
  429.                         {
  430.                             FreeVecPooled(SoundInfo);
  431.  
  432.                             SoundInfo = NULL;
  433.                         }
  434.                     }
  435.                 }
  436.  
  437.                 CloseIFF(Handle);
  438.             }
  439.  
  440.             Close(Handle -> iff_Stream);
  441.         }
  442.  
  443.         FreeIFF(Handle);
  444.     }
  445.  
  446.         /* Successful? */
  447.  
  448.     if(SoundInfo)
  449.         strcpy(SoundInfo -> Name,Name);
  450.     else
  451.     {
  452.         if(Warn)
  453.             MyEasyRequest(Window,LocaleString(MSG_TERMSOUND_COULD_NOT_LOAD_SOUND_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Name);
  454.     }
  455.  
  456.     return(SoundInfo);
  457. }
  458.  
  459.     /* ReplaySound():
  460.      *
  461.      *    Replay sound with given information (doubly-buffered).
  462.      */
  463.  
  464. STATIC VOID __inline
  465. ReplaySound(struct SoundInfo *SoundInfo,struct IOAudio *SoundControlRequest,struct IOAudio *SoundRequestLeft,struct IOAudio *SoundRequestRight,struct BufferInfo *BufferInfo)
  466. {
  467.     UBYTE    *Left    = SoundInfo -> LeftData,
  468.         *Right    = SoundInfo -> RightData;
  469.     ULONG     Size    = SoundInfo -> Length,Length;
  470.     WORD     Base    = 0;
  471.  
  472.     Length = MIN(BUFFER_SIZE,Size);
  473.  
  474.     Size -= Length;
  475.  
  476.         /* Left channel available? */
  477.  
  478.     if(!(((ULONG)SoundRequestLeft -> ioa_Request . io_Unit) & (LEFT0F | LEFT1F)))
  479.         Left = NULL;
  480.  
  481.         /* Right channel available? */
  482.  
  483.     if(!(((ULONG)SoundRequestRight -> ioa_Request . io_Unit) & (RIGHT0F | RIGHT1F)))
  484.         Right = NULL;
  485.  
  486.         /* Fill up left buffer. */
  487.  
  488.     if(Left)
  489.     {
  490.         CopyMem(Left,BufferInfo[Base] . Buffer,Length);
  491.  
  492.         BufferInfo[Base] . Size = Length;
  493.  
  494.         Left += Length;
  495.     }
  496.  
  497.         /* Fill up right buffer. */
  498.  
  499.     if(Right)
  500.     {
  501.         CopyMem(Right,BufferInfo[Base + 2] . Buffer,Length);
  502.  
  503.         BufferInfo[Base + 2] . Size = Length;
  504.  
  505.         Right += Length;
  506.     }
  507.  
  508.         /* Process sound data. */
  509.  
  510.     do
  511.     {
  512.             /* Block both channels. */
  513.  
  514.         SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  515.  
  516.         SendIO(SoundControlRequest);
  517.         WaitIO(SoundControlRequest);
  518.  
  519.             /* Any data for the left channel? */
  520.  
  521.         if(Left)
  522.         {
  523.             SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  524.             SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  525.             SoundRequestLeft -> ioa_Period            = SoundInfo -> Rate;
  526.             SoundRequestLeft -> ioa_Volume            = SoundInfo -> Volume;
  527.             SoundRequestLeft -> ioa_Cycles            = 1;
  528.             SoundRequestLeft -> ioa_Data            = BufferInfo[Base] . Buffer;
  529.             SoundRequestLeft -> ioa_Length            = BufferInfo[Base] . Size;
  530.  
  531.                 /* Get the left channel going. */
  532.  
  533.             BeginIO(SoundRequestLeft);
  534.         }
  535.  
  536.             /* Any data for the right channel? */
  537.  
  538.         if(Right)
  539.         {
  540.             SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  541.             SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  542.             SoundRequestRight -> ioa_Period            = SoundInfo -> Rate;
  543.             SoundRequestRight -> ioa_Volume            = SoundInfo -> Volume;
  544.             SoundRequestRight -> ioa_Cycles            = 1;
  545.             SoundRequestRight -> ioa_Data            = BufferInfo[Base + 2] . Buffer;
  546.             SoundRequestRight -> ioa_Length            = BufferInfo[Base + 2] . Size;
  547.  
  548.                 /* Get the right channel going. */
  549.  
  550.             BeginIO(SoundRequestRight);
  551.         }
  552.  
  553.             /* Start up both channels synchronously... */
  554.  
  555.         SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  556.  
  557.         SendIO(SoundControlRequest);
  558.         WaitIO(SoundControlRequest);
  559.  
  560.             /* Grab the other buffers. */
  561.  
  562.         Base ^= 1;
  563.  
  564.             /* Still any data left? */
  565.  
  566.         if(Size)
  567.         {
  568.                 /* Cut off the next slice. */
  569.  
  570.             Length = MIN(BUFFER_SIZE,Size);
  571.  
  572.             Size -= Length;
  573.  
  574.                 /* Left channel available? */
  575.  
  576.             if(Left)
  577.             {
  578.                 CopyMem(Left,BufferInfo[Base] . Buffer,Length);
  579.  
  580.                 BufferInfo[Base] . Size = Length;
  581.  
  582.                 Left += Length;
  583.             }
  584.  
  585.                 /* Right channel available? */
  586.  
  587.             if(Right)
  588.             {
  589.                 CopyMem(Right,BufferInfo[Base + 2] . Buffer,Length);
  590.  
  591.                 BufferInfo[Base + 2] . Size = Length;
  592.  
  593.                 Right += Length;
  594.             }
  595.  
  596.                 /* Last slice eaten? */
  597.  
  598.             if(!Size)
  599.             {
  600.                     /* Wait for sounds to terminate. */
  601.  
  602.                 if(Left)
  603.                     WaitIO(SoundRequestLeft);
  604.  
  605.                 if(Right)
  606.                     WaitIO(SoundRequestRight);
  607.  
  608.                     /* Block both channels. */
  609.  
  610.                 SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  611.  
  612.                 SendIO(SoundControlRequest);
  613.                 WaitIO(SoundControlRequest);
  614.  
  615.                     /* Any data for the left channel? */
  616.  
  617.                 if(Left)
  618.                 {
  619.                     SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  620.                     SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  621.                     SoundRequestLeft -> ioa_Period            = SoundInfo -> Rate;
  622.                     SoundRequestLeft -> ioa_Volume            = SoundInfo -> Volume;
  623.                     SoundRequestLeft -> ioa_Cycles            = 1;
  624.                     SoundRequestLeft -> ioa_Data            = BufferInfo[Base] . Buffer;
  625.                     SoundRequestLeft -> ioa_Length            = BufferInfo[Base] . Size;
  626.  
  627.                         /* Get the left channel going. */
  628.  
  629.                     BeginIO(SoundRequestLeft);
  630.                 }
  631.  
  632.                     /* Any data for the right channel? */
  633.  
  634.                 if(Right)
  635.                 {
  636.                     SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  637.                     SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  638.                     SoundRequestRight -> ioa_Period            = SoundInfo -> Rate;
  639.                     SoundRequestRight -> ioa_Volume            = SoundInfo -> Volume;
  640.                     SoundRequestRight -> ioa_Cycles            = 1;
  641.                     SoundRequestRight -> ioa_Data            = BufferInfo[Base + 2] . Buffer;
  642.                     SoundRequestRight -> ioa_Length            = BufferInfo[Base + 2] . Size;
  643.  
  644.                         /* Get the right channel going. */
  645.  
  646.                     BeginIO(SoundRequestRight);
  647.                 }
  648.  
  649.                     /* Start up both channels synchronously... */
  650.  
  651.                 SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  652.  
  653.                 SendIO(SoundControlRequest);
  654.                 WaitIO(SoundControlRequest);
  655.             }
  656.         }
  657.  
  658.             /* Wait for sounds to terminate. */
  659.  
  660.         if(Left)
  661.             WaitIO(SoundRequestLeft);
  662.  
  663.         if(Right)
  664.             WaitIO(SoundRequestRight);
  665.     }
  666.     while(Size);
  667. }
  668.  
  669.     /* PlaySound(struct SoundInfo *SoundInfo):
  670.      *
  671.      *    Replay a sound.
  672.      */
  673.  
  674. VOID __regargs
  675. PlaySound(struct SoundInfo *SoundInfo)
  676. {
  677.     struct BufferInfo *BufferInfo;
  678.  
  679.         /* Allocate sound buffers. */
  680.  
  681.     if(BufferInfo = (struct BufferInfo *)AllocVec(4 * sizeof(struct BufferInfo),MEMF_CHIP))
  682.     {
  683.         struct MsgPort *SoundPort;
  684.  
  685.             /* Allocate an io replyport. */
  686.  
  687.         if(SoundPort = CreateMsgPort())
  688.         {
  689.             struct IOAudio *SoundControlRequest;
  690.  
  691.                 /* Allocate the big sound control request. */
  692.  
  693.             if(SoundControlRequest = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  694.             {
  695.                 struct IOAudio *SoundRequestLeft;
  696.  
  697.                     /* Allocate the left channel sound request. */
  698.  
  699.                 if(SoundRequestLeft = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  700.                 {
  701.                     struct IOAudio *SoundRequestRight;
  702.  
  703.                         /* Allocate the right channel sound request. */
  704.  
  705.                     if(SoundRequestRight = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  706.                     {
  707.                         STATIC UBYTE TwoChannels[] =
  708.                         {
  709.                             LEFT0F | RIGHT0F,
  710.                             LEFT0F | RIGHT1F,
  711.                             LEFT1F | RIGHT0F,
  712.                             LEFT1F | RIGHT1F
  713.                         };
  714.  
  715.                         STATIC UBYTE LeftChannel[] =
  716.                         {
  717.                             LEFT0F,
  718.                             LEFT1F
  719.                         };
  720.  
  721.                         STATIC UBYTE RightChannel[] =
  722.                         {
  723.                             RIGHT0F,
  724.                             RIGHT1F
  725.                         };
  726.  
  727.                         UBYTE    *AllocationMap;
  728.                         LONG     AllocationSize;
  729.  
  730.                             /* Determine the correct channel
  731.                              * allocation map.
  732.                              */
  733.  
  734.                         if(SoundInfo -> LeftData)
  735.                         {
  736.                             if(SoundInfo -> RightData)
  737.                             {
  738.                                 AllocationMap    = TwoChannels;
  739.                                 AllocationSize    = sizeof(TwoChannels);
  740.                             }
  741.                             else
  742.                             {
  743.                                 AllocationMap    = LeftChannel;
  744.                                 AllocationSize    = sizeof(LeftChannel);
  745.                             }
  746.                         }
  747.                         else
  748.                         {
  749.                             AllocationMap    = RightChannel;
  750.                             AllocationSize    = sizeof(RightChannel);
  751.                         }
  752.  
  753.                             /* Set up for sound channel allocation. */
  754.  
  755.                         SoundControlRequest -> ioa_Request . io_Message . mn_Node . ln_Pri    = 80;
  756.                         SoundControlRequest -> ioa_Request . io_Command                = ADCMD_ALLOCATE;
  757.                         SoundControlRequest -> ioa_Request . io_Flags                = ADIOF_NOWAIT | ADIOF_PERVOL;
  758.                         SoundControlRequest -> ioa_Data                        = AllocationMap;
  759.                         SoundControlRequest -> ioa_Length                    = AllocationSize;
  760.  
  761.                             /* Open audio.device, allocating the sound
  762.                              * channels on the fly.
  763.                              */
  764.  
  765.                         if(!OpenDevice(AUDIONAME,NULL,SoundControlRequest,NULL))
  766.                         {
  767.                                 /* Clone the sound control request. */
  768.  
  769.                             CopyMem(SoundControlRequest,SoundRequestLeft,    sizeof(struct IOAudio));
  770.                             CopyMem(SoundControlRequest,SoundRequestRight,    sizeof(struct IOAudio));
  771.  
  772.                                 /* Separate the channels. */
  773.  
  774.                             SoundRequestLeft  -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestLeft  -> ioa_Request . io_Unit & (LEFT0F  | LEFT1F));
  775.                             SoundRequestRight -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestRight -> ioa_Request . io_Unit & (RIGHT0F | RIGHT1F));
  776.  
  777.                                 /* Replay the sound... */
  778.  
  779.                             ReplaySound(SoundInfo,SoundControlRequest,SoundRequestLeft,SoundRequestRight,BufferInfo);
  780.  
  781.                                 /* Do the big cleanup. */
  782.  
  783.                             CloseDevice(SoundControlRequest);
  784.                         }
  785.  
  786.                         DeleteIORequest(SoundRequestRight);
  787.                     }
  788.  
  789.                     DeleteIORequest(SoundRequestLeft);
  790.                 }
  791.  
  792.                 DeleteIORequest(SoundControlRequest);
  793.             }
  794.  
  795.             DeleteMsgPort(SoundPort);
  796.         }
  797.  
  798.         FreeVec(BufferInfo);
  799.     }
  800. }
  801.  
  802.     /* SoundLoad(WORD Sound,BYTE Warn):
  803.      *
  804.      *    Loads or frees a sound slot.
  805.      */
  806.  
  807. STATIC BYTE __regargs
  808. SoundLoad(WORD Sound,BYTE Warn)
  809. {
  810.     struct SoundInfo    **Info = &SoundSlot[Sound];
  811.     STRPTR            Name;
  812.     BYTE            Success = FALSE;
  813.  
  814.         /* Which sound file name are we to pick? */
  815.  
  816.     switch(Sound)
  817.     {
  818.         case SOUND_BELL:
  819.  
  820.             Name = SoundConfig . BellFile;
  821.             break;
  822.  
  823.         case SOUND_CONNECT:
  824.  
  825.             Name = SoundConfig . ConnectFile;
  826.             break;
  827.  
  828.         case SOUND_DISCONNECT:
  829.  
  830.             Name = SoundConfig . DisconnectFile;
  831.             break;
  832.  
  833.         case SOUND_GOODTRANSFER:
  834.  
  835.             Name = SoundConfig . GoodTransferFile;
  836.             break;
  837.  
  838.         case SOUND_BADTRANSFER:
  839.  
  840.             Name = SoundConfig . BadTransferFile;
  841.             break;
  842.  
  843.         case SOUND_RING:
  844.  
  845.             Name = SoundConfig . RingFile;
  846.             break;
  847.  
  848.         case SOUND_VOICE:
  849.  
  850.             Name = SoundConfig . VoiceFile;
  851.             break;
  852.     }
  853.  
  854.         /* Is a file name available? */
  855.  
  856.     if(Name[0])
  857.     {
  858.             /* Sound slot already initialized? */
  859.  
  860.         if(*Info)
  861.         {
  862.                 /* Did the file name change? */
  863.  
  864.             if(Stricmp((*Info) -> Name,Name))
  865.             {
  866.                     /* Free the sound slot. */
  867.  
  868.                 FreeSound(*Info);
  869.  
  870.                     /* Try to load the sound slot. */
  871.  
  872.                 if(*Info = LoadSound(Name,Warn))
  873.                 {
  874.                         /* Remember the file name. */
  875.  
  876.                     strcpy((*Info) -> Name,Name);
  877.  
  878.                     Success = TRUE;
  879.                 }
  880.             }
  881.             else
  882.                 Success = TRUE;
  883.         }
  884.         else
  885.         {
  886.                 /* Try to load the sound slot. */
  887.  
  888.             if(*Info = LoadSound(Name,Warn))
  889.             {
  890.                     /* Remember the file name. */
  891.  
  892.                 strcpy((*Info) -> Name,Name);
  893.  
  894.                 Success = TRUE;
  895.             }
  896.         }
  897.     }
  898.     else
  899.     {
  900.             /* Does the slot still contain any sound? */
  901.  
  902.         if(*Info)
  903.         {
  904.                 /* Free the slot. */
  905.  
  906.             FreeSound(*Info);
  907.  
  908.             *Info = NULL;
  909.         }
  910.  
  911.         Success = TRUE;
  912.     }
  913.  
  914.     return(Success);
  915. }
  916.  
  917.     /* SoundServer(VOID):
  918.      *
  919.      *    Replay a sound.
  920.      */
  921.  
  922. STATIC VOID __saveds
  923. SoundServer(VOID)
  924. {
  925.     LONG Sound = (LONG)SysBase -> ThisTask -> tc_UserData;
  926.  
  927.         /* Get exclusive access to the sound slots. */
  928.  
  929.     ObtainSemaphore(SoundSemaphore);
  930.  
  931.         /* Replay the sound. */
  932.  
  933.     PlaySound(SoundSlot[Sound]);
  934.  
  935.     Forbid();
  936.  
  937.         /* Release access to the sound slots. */
  938.  
  939.     ReleaseSemaphore(SoundSemaphore);
  940.  
  941.         /* Remove ourselves. */
  942.  
  943.     RemTask(NULL);
  944. }
  945.  
  946.     /* SoundExit():
  947.      *
  948.      *    Free allocated sound resources.
  949.      */
  950.  
  951. VOID
  952. SoundExit()
  953. {
  954.     WORD i;
  955.  
  956.         /* Access semaphore available? */
  957.  
  958.     if(SoundSemaphore)
  959.     {
  960.         ObtainSemaphore(SoundSemaphore);
  961.  
  962.         ReleaseSemaphore(SoundSemaphore);
  963.  
  964.         FreeVecPooled(SoundSemaphore);
  965.  
  966.         SoundSemaphore = NULL;
  967.     }
  968.  
  969.         /* Free the slots. */
  970.  
  971.     for(i = 0 ; i < SOUND_COUNT ; i++)
  972.     {
  973.         if(SoundSlot[i])
  974.         {
  975.             FreeSound(SoundSlot[i]);
  976.  
  977.             SoundSlot[i] = NULL;
  978.         }
  979.     }
  980. }
  981.  
  982.     /* SoundInit():
  983.      *
  984.      *    Allocate resources required for sound replaying.
  985.      */
  986.  
  987. VOID
  988. SoundInit()
  989. {
  990.         /* Sound access semaphore available? */
  991.  
  992.     if(SoundSemaphore)
  993.     {
  994.         ObtainSemaphore(SoundSemaphore);
  995.         ReleaseSemaphore(SoundSemaphore);
  996.     }
  997.     else
  998.     {
  999.         if(SoundSemaphore = (struct SignalSemaphore *)AllocVecPooled(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  1000.             InitSemaphore(SoundSemaphore);
  1001.     }
  1002.  
  1003.         /* Preload sounds if necessary. */
  1004.  
  1005.     if(SoundSemaphore && SoundConfig . Preload)
  1006.     {
  1007.         WORD i;
  1008.  
  1009.         for(i = 0 ; i < SOUND_COUNT ; i++)
  1010.             SoundLoad(i,TRUE);
  1011.     }
  1012. }
  1013.  
  1014.     /* SoundPlay(WORD Sound):
  1015.      *
  1016.      *    Play a certain sound slot.
  1017.      */
  1018.  
  1019. VOID __regargs
  1020. SoundPlay(WORD Sound)
  1021. {
  1022.         /* Sound access semaphore available? */
  1023.  
  1024.     if(SoundSemaphore)
  1025.     {
  1026.         if(SoundConfig . Volume)
  1027.         {
  1028.                 /* Check to see if we are currently playing a
  1029.                  * sound.
  1030.                  */
  1031.  
  1032.             if(!AttemptSemaphore(SoundSemaphore))
  1033.                 return;
  1034.             else
  1035.                 ReleaseSemaphore(SoundSemaphore);
  1036.  
  1037.                 /* Release any other sound if necessary. */
  1038.  
  1039.             if(!SoundConfig . Preload)
  1040.             {
  1041.                 WORD i;
  1042.  
  1043.                 for(i = 0 ; i < SOUND_COUNT ; i++)
  1044.                 {
  1045.                     if(i != Sound && SoundSlot[i])
  1046.                     {
  1047.                         FreeSound(SoundSlot[i]);
  1048.  
  1049.                         SoundSlot[i] = NULL;
  1050.                     }
  1051.                 }
  1052.             }
  1053.  
  1054.                 /* Load the sound slot. */
  1055.  
  1056.             SoundLoad(Sound,FALSE);
  1057.  
  1058.                 /* Slot filled? */
  1059.  
  1060.             if(SoundSlot[Sound])
  1061.             {
  1062.                 struct Task    *SoundTask;
  1063.                 LONG         Pri = ThisProcess -> pr_Task . tc_Node . ln_Pri + 10;
  1064.  
  1065.                     /* Priority raised, check for limit. */
  1066.  
  1067.                 if(Pri > 127)
  1068.                     Pri = 127;
  1069.  
  1070.                 Forbid();
  1071.  
  1072.                     /* Fire off the sound server task. */
  1073.  
  1074.                 if(SoundTask = CreateTask("term Sound Task",Pri,SoundServer,4096))
  1075.                     SoundTask -> tc_UserData = (APTR)Sound;
  1076.  
  1077.                 Permit();
  1078.             }
  1079.             else
  1080.                 Beep();
  1081.         }
  1082.     }
  1083.     else
  1084.         Beep();
  1085. }
  1086.